package com.gnerv.battle.boot.module.base.business.impl;

import com.gnerv.battle.boot.common.base.model.RestResult;
import com.gnerv.battle.boot.common.tools.GsonTools;
import com.gnerv.battle.boot.common.tools.UUIDTools;
import com.gnerv.battle.boot.module.base.business.RoleBusiness;
import com.gnerv.battle.boot.module.base.model.bo.RoleBO;
import com.gnerv.battle.boot.module.base.model.bo.RoleDatePermissionBO;
import com.gnerv.battle.boot.module.base.model.dto.RoleAccountDTO;
import com.gnerv.battle.boot.module.base.model.dto.RoleCreateDTO;
import com.gnerv.battle.boot.module.base.model.dto.RoleDTO;
import com.gnerv.battle.boot.module.base.model.dto.RolePermissionDTO;
import com.gnerv.battle.boot.module.base.model.dto.RoleUpdateDTO;
import com.gnerv.battle.boot.module.base.model.dto.RoleViewDTO;
import com.gnerv.battle.boot.module.base.model.entity.RoleDataPermission;
import com.gnerv.battle.boot.module.base.service.CurrentAccountService;
import com.gnerv.battle.boot.module.base.service.OrgService;
import com.gnerv.battle.boot.module.base.service.RoleDataPermissionService;
import com.gnerv.battle.boot.module.base.service.RoleService;
import com.google.common.reflect.TypeToken;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.List;

/**
 * @author Gnerv LiGen
 */
@Slf4j
@Service
@AllArgsConstructor
public class RoleBusinessImpl implements RoleBusiness {

    private final RoleService roleService;
    private final OrgService orgService;
    private final RoleDataPermissionService roleDataPermissionService;
    private final CurrentAccountService currentAccountService;

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public RestResult<Void> create(RoleCreateDTO roleCreateDTO) {
        RoleBO roleBO = roleCreateDTO.toRoleBO();
        roleBO.setUkId(UUIDTools.lower());
        roleService.create(roleBO);
        RoleDatePermissionBO roleDatePermissionBO = roleCreateDTO.toRoleDatePermissionBO();
        roleDatePermissionBO.setRoleUkId(roleBO.getUkId());
        String accountUkId = currentAccountService.accountUkId();
        List<String> roleUkIdList = roleService.listUkIdByAccountUkId(accountUkId);
        roleDatePermissionBO.getRoleUkIdList().addAll(roleUkIdList);
        String orgUkId = orgService.selectUkIdByAccountUkId(accountUkId);
        if(StringUtils.hasText(orgUkId)){
            roleDatePermissionBO.getOrgUkIdList().add(orgUkId);
        }
        roleDataPermissionService.insert(roleDatePermissionBO);
        return RestResult.ok();
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public RestResult<Void> deleteByUkId(String ukId) {
        roleService.deleteByUkId(ukId);
        roleService.unbindAccount(ukId);
        roleService.unbindPermission(ukId);
        roleService.unbindView(ukId);
        roleDataPermissionService.deleteByRoleUkId(ukId);
        return RestResult.ok();
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public RestResult<Void> updateByUkId(RoleUpdateDTO roleUpdateDTO) {
        roleService.updateByUkId(roleUpdateDTO.toRoleBO());
        RoleDatePermissionBO roleDatePermissionBO = roleUpdateDTO.toRoleDatePermissionBO();
        String accountUkId = currentAccountService.accountUkId();
        List<String> roleUkIdList = roleService.listUkIdByAccountUkId(accountUkId);
        roleDatePermissionBO.getRoleUkIdList().addAll(roleUkIdList);
        String orgUkId = orgService.selectUkIdByAccountUkId(accountUkId);
        if(StringUtils.hasText(orgUkId)){
            roleDatePermissionBO.getOrgUkIdList().add(orgUkId);
        }
        roleDataPermissionService.insert(roleDatePermissionBO);
        roleDataPermissionService.updateByRoleUkId(roleDatePermissionBO);
        return RestResult.ok();
    }

    @Override
    @Transactional(readOnly = true)
    public RestResult<RoleDTO> selectByUkId(String ukId) {
        RoleDTO roleDTO = roleService.selectByUkId(ukId);
        RoleDataPermission roleDataPermission = roleDataPermissionService.selectByRoleUkId(ukId);
        roleDTO.setRoleUkIdList(GsonTools.GSON.fromJson(roleDataPermission.getRole(), new TypeToken<List<String>>() {
        }.getType()));
        roleDTO.setOrgUkIdList(GsonTools.GSON.fromJson(roleDataPermission.getOrg(), new TypeToken<List<String>>() {
        }.getType()));
        return RestResult.ok(roleDTO);
    }

    @Override
    @Transactional(readOnly = true)
    public RestResult<List<RoleDTO>> listByName(String name) {
        return RestResult.ok(roleService.listByName(name));
    }

    @Override
    public RestResult<Void> bindAccount(RoleAccountDTO roleAccountDTO) {
        roleService.unbindAccount(roleAccountDTO.getRoleUkId());
        roleService.bindAccount(roleAccountDTO.getRoleUkId(), roleAccountDTO.getAccountUkIdList());
        return RestResult.ok();
    }

    @Override
    public RestResult<Void> bindPermission(RolePermissionDTO rolePermissionDTO) {
        roleService.unbindPermission(rolePermissionDTO.getRoleUkId());
        roleService.bindPermission(rolePermissionDTO.getRoleUkId(), rolePermissionDTO.getPermissionUkIdList());
        return RestResult.ok();
    }

    @Override
    public RestResult<Void> bindView(RoleViewDTO roleViewDTO) {
        roleService.unbindView(roleViewDTO.getRoleUkId());
        roleService.bindView(roleViewDTO.getRoleUkId(), roleViewDTO.getViewUkIdList());
        return RestResult.ok();
    }

}
